﻿namespace HostTracker.Azure.Management

open System
open System.ServiceModel
open System.ServiceModel.Web
open System.Runtime.Serialization
open System.Net
open System.IO
open FSharpExtensions

(*
<?xml version="1.0" encoding="utf-8"?>
<CertificateFile xmlns=”http://schemas.microsoft.com/windowsazure”>
  <Data>base64-encoded-pfx-file</Data>
  <CertificateFormat>pfx</CertificateFormat>
  <Password>pfx-file-password</Password>
</CertificateFile>
*)
[<DataContract(Name = "CertificateFile", Namespace = "http://schemas.microsoft.com/windowsazure")>]
type Certificate(password: string, certFormat) =
    let mutable data: byte[] = Array.empty
    new (password) = Certificate(password, "pfx")
    [<DataMember(Name = "Data", Order = 1)>]
    member private x.DataEncoded with get() = Convert.ToBase64String(data) and set (v: string) = data <- Convert.FromBase64String(v)
    member x.Data with get () = data and set v = data <- v
    [<DataMember(Name = "CertificateFormat", Order = 2)>]
    member x.CertificateFormat with get () = certFormat and set _ = ()
    [<DataMember(Name = "Password", Order = 3)>]
    member x.Password with get () = password and set _ = ()
    static member LoadFromFile(path, password: string) =
        if (Path.GetExtension(path) = ".pfx") then
            use stream = File.OpenRead(path)
            let length = (int)stream.Length
            let bytes = Array.zeroCreate length
            stream.Read(bytes, 0, length) |> ignore
            Certificate(password, Data = bytes)
        else 
            failwith "Unsupported certificate format"

(*
<?xml version="1.0" encoding="utf-8"?>
  <Certificates xmlns=”http://schemas.microsoft.com/windowsazure”>
    <Certificate>
      <CertificateUrl>certificate-thumbprint-address</CertificateUrl>
      <Thumbprint>certificate-thumbprint</Thumbprint>
      <ThumbprintAlgorithm>thumbprint-algorithm</ThumbprintAlgorithm>        
      <Data>base64-encoded-X509-representation-of-the-certificate</Data>
    </Certificate>
  </Certificates>
*)
[<DataContract(Name = "Certificate", Namespace = "http://schemas.microsoft.com/windowsazure")>]
type CertificateDescription() =
    let mutable url = ""
    let mutable thumbprint = ""
    let mutable thumbprintAlg = ""
    let mutable data: byte [] = Array.empty
    [<DataMember(Name = "CertificateUrl", Order = 1, IsRequired = false)>]
    member x.Url with get () = url and set v = url <- v
    [<DataMember(Name = "Thumbprint", Order = 2, IsRequired = false)>]
    member x.Thumbprint with get () = thumbprint and set v = thumbprint <- v
    [<DataMember(Name = "ThumbprintAlgorithm", Order = 3, IsRequired = false)>]
    member x.ThumbprintAlgorithm with get () = thumbprintAlg and set v = thumbprintAlg <- v
    [<DataMember(Name = "Data", Order = 4)>]
    member private x.DataEncoded with get() = Convert.ToBase64String(data) and set v = data <- Convert.FromBase64String(v)
    member x.Data = data

[<CollectionDataContract(Name = "Certificates", Namespace = "http://schemas.microsoft.com/windowsazure")>]
type Certificates() = inherit System.Collections.Generic.List<CertificateDescription>()

[<Interface>]
[<ServiceContractAttribute>]
type ICertificatesManagement =
    [<OperationContract>]
    [<WebInvoke(UriTemplate="/services/hostedservices/{serviceName}/certificates", Method="POST")>]
    abstract CreateCertificate: serviceName:string*cert:Certificate -> unit
    [<OperationContract(AsyncPattern = true)>]
    abstract BeginCreateCertificate: serviceName:string*cert:Certificate*callback:AsyncCallback*state:obj -> IAsyncResult
    abstract EndCreateCertificate: result:IAsyncResult -> unit
    [<OperationContract>]
    [<WebInvoke(UriTemplate="/services/hostedservices/{serviceName}/certificates", Method="GET")>]
    abstract ListCertificates: serviceName:string -> Certificates
    [<OperationContract(AsyncPattern = true)>]
    abstract BeginListCertificates: serviceName:string*callback:AsyncCallback*state:obj -> IAsyncResult
    abstract EndListCertificates: result:IAsyncResult -> Certificates
    [<OperationContract>]
    [<WebInvoke(UriTemplate="/services/hostedservices/{serviceName}/certificates/{alg}-{thumbprint}", Method="GET")>]
    abstract GetCertificate: serviceName:string*alg:string*thumbprint:string -> CertificateDescription
    [<OperationContract(AsyncPattern = true)>]
    abstract BeginGetCertificate: serviceName:string*alg:string*thumbprint:string*callback:AsyncCallback*state:obj -> IAsyncResult
    abstract EndGetCertificate: result:IAsyncResult -> CertificateDescription
    [<OperationContract>]
    [<WebInvoke(UriTemplate="/services/hostedservices/{serviceName}/certificates/{alg}-{thumbprint}", Method="DELETE")>]
    abstract DeleteCertificate: serviceName:string*alg:string*thumbprint:string -> unit
    [<OperationContract(AsyncPattern = true)>]
    abstract BeginDeleteCertificate: serviceName:string*alg:string*thumbprint:string*callback:AsyncCallback*state:obj -> IAsyncResult
    abstract EndDeleteCertificate: result:IAsyncResult -> unit